<pre class=metadata>
title: ES pipe operator (2021)
status: proposal
stage: 2
location: https://github.com/tc39/proposal-pipeline-operator
copyright: false
contributors: J. S. Choi, James DiGioia, Ron Buckton, Tab Atkins-Bittner
</pre>
<script src=ecmarkup.js defer></script>
<link rel=stylesheet href=ecmarkup.css>

<emu-intro id=introduction>
  <h1>Introduction</h1>
  <p>This is the formal specification for a proposed Hack-style pipe
  operator `|&gt;` in JavaScript. It modifies the original <a
  href=https://tc39.github.io/ecma262/>ECMAScript specification</a> with
  several new or revised clauses. See <a
  href=https://github.com/js-choi/proposal-hack-pipes/blob/main/README.md>the proposal's
  explainer</a> for the proposal's background, motivation, and usage examples.</p>

  <p>This document presumptively uses `%` as the token
  for the topic reference. This choice of token is not a final decision;
  `%` could instead be `^` or some other token.</p>
</emu-intro>

<emu-clause id="sec-syntax-directed-operations">
  <h1>Syntax-Directed Operations</h1>

  <emu-clause id="sec-syntax-directed-operations-function-name-inference">
    <h1>Function Name Inference</h1>

    <emu-clause id="sec-static-semantics-isfunctiondefinition" type="sdo"
    aoid="IsFunctionDefinition">
      <h1>Static Semantics: IsFunctionDefinition</h1>

      <emu-note type=editor>
        <p>This section augments the <a
        href=https://tc39.es/ecma262/#sec-static-semantics-isfunctiondefinition>original
        IsFunctionDefinition clause</a>.</p>

        <p>It presumptively uses `%` as the placeholder token for the
        topic reference. This choice of token is not a final decision; `%`
        could instead be `^` or some other token.</p>
      </emu-note>

      <emu-grammar>
        PrimaryExpression :
          `this`
          <ins>`%`</ins>
          IdentifierReference
          Literal
          ArrayLiteral
          ObjectLiteral
          RegularExpressionLiteral
          TemplateLiteral

        <ins>PipeExpression :
          ShortCircuitExpression `|&gt;` PipeBody</ins>
      </emu-grammar>
      <emu-alg>
        1. Return *false*.
      </emu-alg>
    </emu-clause>

    <emu-clause id="sec-static-semantics-isidentifierref" type="sdo"
    aoid="IsIdentifierRef">
      <h1>Static Semantics: IsIdentifierRef</h1>

      <emu-note type=editor>
        <p>This section augments the <a
        href=https://tc39.es/ecma262/#sec-static-semantics-isidentifierref>original IsIdentifierRef
        clause</a>.</p>

        <p>It presumptively uses `%` as the placeholder token for the
        topic reference. This choice of token is not a final decision; `%`
        could instead be `^` or some other token.</p>
      </emu-note>

      <emu-grammar>PrimaryExpression : IdentifierReference</emu-grammar>
      <emu-alg>
        1. Return *true*.
      </emu-alg>
      <emu-grammar>
        PrimaryExpression :
          `this`
          <ins>`%`</ins>
          Literal
          ArrayLiteral
          ObjectLiteral
          FunctionExpression
          ClassExpression
          GeneratorExpression
          AsyncFunctionExpression
          AsyncGeneratorExpression
          RegularExpressionLiteral
          TemplateLiteral
          CoverParenthesizedExpressionAndArrowParameterList
      </emu-grammar>
      <emu-alg>
        1. Return *false*.
      </emu-alg>
    </emu-clause>
  </emu-clause>

  <emu-clause id="sec-syntax-directed-operations-contains">
    <h1>Contains</h1>

    <emu-clause id="sec-static-semantics-ContainsOuterTopic" type="sdo" aoid="ContainsOuterTopic">
      <h1>Static Semantics: ContainsOuterTopic</h1>
      <emu-note type=editor>
        <p>This section is a wholly new sub-clause of the <a
        href=https://tc39.github.io/ecma262/#sec-syntax-directed-operations-contains
        >original Contains clause</a>.</p>
      </emu-note>

      <emu-note>
        <p>Several early error rules for |ScriptBody| and for
        |ModuleItemList|, as well as a step in CreateDynamicFunction,
        use the ContainsOuterTopic operation to check for any unbound topic reference `%`.
        Any inner topic reference within a |PipeBody| is hidden from these rules,
        preventing them from triggering the rules during program
        compilation.</p>

        <p>This guarantees that any topic reference in a program must be
        present within a topic-binding environment
        created by a |PipeBody| within that program.</p>
      </emu-note>

      <p>Every grammar production alternative in this specification which is not listed below implicitly has the following default definition of ContainsOuterTopic:</p>

      <emu-alg>
        1. For each child node _child_ of this Parse Node, do
          1. If _child_ is an instance of `%`, return *true*.
          1. If _child_ is an instance of a nonterminal, and if ContainsOuterTopic of _child_ is *true*, return *true*.
        1. Return *false*.
      </emu-alg>

      <emu-grammar>MultiplicativeExpression : MultiplicativeExpression MultiplicativeOperator ExponentiationExpression</emu-grammar>

      <emu-alg>
        1. If ContainsOuterTopic of |MultiplicativeExpression| is *true*, or if ContainsOuterTopic of |ExponentiationExpression| is *true*, return *true*.
        1. Return *false*.
      </emu-alg>

      <emu-grammar>PipeBody : AssignmentExpression</emu-grammar>

      <emu-alg>
        1. Return *false*.
      </emu-alg>
    </emu-clause>
  </emu-clause>

  <emu-clause id="sec-syntax-directed-operations-miscellaneous">
    <h1>Miscellaneous</h1>

    <emu-clause id="sec-static-semantics-assignmenttargettype" type="sdo"
    aoid="AssignmentTargetType">
      <h1>Static Semantics: AssignmentTargetType</h1>

      <emu-note type=editor>
        <p>This section augments the <a
        href=https://tc39.es/ecma262/#sec-static-semantics-assignmenttargettype>original
        AssignmentTargetType clause</a>.</p>

        <p>It presumptively uses `%` as the placeholder token for the
        topic reference. This choice of token is not a final decision; `%`
        could instead be `^` or some other token.</p>
      </emu-note>

      <emu-grammar>
        PrimaryExpression :
          `this`
          <ins>`%`</ins>
          Literal
          ArrayLiteral
          ObjectLiteral
          FunctionExpression
          ClassExpression
          GeneratorExpression
          AsyncFunctionExpression
          AsyncGeneratorExpression
          RegularExpressionLiteral
          TemplateLiteral

        <ins>PipeExpression :
          ShortCircuitExpression `|&gt;` PipeBody</ins>
      </emu-grammar>
      <emu-alg>
        1. Return ~invalid~.
      </emu-alg>
    </emu-clause>
  </emu-clause>
</emu-clause>

<emu-clause id=executable-code-and-execution-contexts>
  <h1>Executable Code and Execution Contexts</h1>

  <emu-clause id=sec-environment-records>
    <h1>Environment Records</h1>

    <emu-clause id=sec-the-environment-record-type-hierarchy>
      <h1>The Environment Record Type Hierarchy</h1>

      <emu-note type=editor>
        <p>This section augments the <a
        href=https://tc39.es/ecma262/#sec-the-environment-record-type-hierarchy>original
        Environment Records clause</a>.</p>
      </emu-note>

      <emu-table id=table-15 caption="Abstract Methods of Environment Records">
        <table>
          <thead>
            <tr>
              <th>Method</th>
              <th>Purpose</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td><ins><emu-xref
                href=#sec-declarative-environment-records-hastopicbinding
                >HasTopicBinding()</emu-xref></ins></td>
              <td><ins>Determine whether an Environment Record is a
                topic-binding environment. Return *true* if it establishes a
                topic binding and *false* if it does not.</ins></td>
            </tr>
          </tbody>
        </table>
      </emu-table>

      <emu-clause id=sec-declarative-environment-records>
        <h1>Declarative Environment Records</h1>

        <emu-note type=editor>
          <p>This section augments the <a
          href=https://tc39.github.io/ecma262/#sec-declarative-environment-records
          >original Declarative Environment Records clause</a>.</p>

          <p>It presumptively uses `%` as the placeholder token for the
          topic reference. This choice of token is not a final decision; `%`
          could instead be `^` or some other token.</p>
        </emu-note>

        <ins class=block>
          <p>Declarative Environment Records have the additional state fields
          listed in <emu-xref href="#table-61"></emu-xref>.</p>

          <emu-table id=table-61
            caption="Additional Fields of Declarative Environment Records"
          >
            <table>
              <thead>
                <tr>
                  <th>Method</th>
                  <th>Value</th>
                  <th>Purpose</th>
                </tr>
              </thead>
              <tbody>
                <tr>
                  <td>[[TopicValues]]</td>
                  <td>List of any</td>
                  <td>If the declarative Environment Record is a topic-binding
                  environment, then [[TopicValues]] is a List containing the one element
                  which is the environment's topic value (that is, the value of
                  the topic reference within its program scope).
                  Otherwise, the value of [[TopicValues]] is an empty List.</td>
                </tr>
              </tbody>
            </table>
          </emu-table>

          <emu-note type=editor>
            <p>[[TopicValues]] is a List in order to be forward compatible with
            future extensions that would use more than one topic value, e.g., <a
         href=https://github.com/js-choi/proposal-hack-pipes/blob/master/README.md#hack-pipe-functions
            >"pipe functions".</a></p>
          </emu-note>

          <p>Declarative Environment Records support all of the abstract methods
          of Environment Records listed in <emu-xref href="#table-15"></emu-xref>.
          In addition, declarative Environment Records support the methods listed
          in <emu-xref href="#table-62"></emu-xref>.</p>

          <emu-table id=table-62 caption="Additional Methods of Declarative Environment Records">
            <table>
              <thead>
                <tr>
                  <th>Method</th>
                  <th>Purpose</th>
                </tr>
              </thead>
              <tbody>
                <tr>
                  <td>BindTopicValues(V)</td>
                  <td>Establish the immutable topic binding of this
                  Environment Record and set the topic binding's value.
                  _V_ is a List containing the one element which is the
                  topic value and is a value of any ECMAScript language
                  type. Afterward, the Environment Record is a
                  topic-binding environment, and the value returned by the
                  Environment Record's HasTopicBinding method is *true*.
                  This method cannot be called more than once on any
                  single Environment Record.</td>
                </tr>
              </tbody>
            </table>
          </emu-table>

          <emu-note type=editor>
          <p>BindTopicValues accepts a List argument rather than a single-value
          argument in order to be forward compatible with future extensions that
          would use more than one topic value, e.g., <a
          href=https://github.com/js-choi/proposal-hack-pipes/blob/master/README.md#hack-pipe-functions
          >"pipe functions"</a>.</p>
          </emu-note>
        </ins>

        <p>The behaviour of the concrete <ins>and additional</ins> specification
        methods for declarative Environment Records is defined by the following
        algorithms.</p>

        <emu-clause id=sec-declarative-environment-records-hastopicbinding>
          <h1><ins>HasTopicBinding ( )</ins></h1>
          <emu-note type=editor>
          <p>This section is a wholly new sub-clause of the <a
          href=https://tc39.github.io/ecma262/#sec-declarative-environment-records
          >original Declarative Environment Records clause</a>.</p>
          </emu-note>

          <p>The concrete Environment Record method HasTopicBinding for
          declarative Environment Records returns whether the Environment Record
          is a topic-binding environment. The value is *true* only if its
          BindTopicValues method has been called.</p>
          <emu-alg>
            1. Let _envRec_ be the declarative Environment Record for which the
               method was invoked.
            1. Assert: _envRec_.[[TopicValues]] is a List.
            1. If _envRec_.[[TopicValues]] is an empty List, then return *false*.
            1. Return *true*.
          </emu-alg>
        </emu-clause>

        <emu-clause id=sec-declarative-environment-records-bindtopicvalues>
          <h1><ins>BindTopicValues ( _V_ )</ins></h1>
          <emu-note type=editor>
            <p>This section is a wholly new sub-clause of the <a
            href=https://tc39.github.io/ecma262/#sec-declarative-environment-records
            >original Declarative Environment Records clause</a>.</p>
          </emu-note>
          <p>The method BindTopicValues for declarative Environment Records may
          only be called on an Environment Record when it is not yet a
          topic-binding environment, after which it does become a topic-binding
          environment.</p>
          <emu-alg>
            1. Assert: _V_ is a List.
            1. Let _envRec_ be the declarative Environment Record for which the
               method was invoked.
            1. Assert: _envRec_.HasTopicBinding() is *false*.
            1. Set _envRec_.[[TopicValues]] to _V_.
            1. Assert: _envRec_.HasTopicBinding() is *true*.
            1. Return NormalCompletion(~empty~).
          </emu-alg>
        </emu-clause>
      </emu-clause>

      <emu-clause id=sec-object-environment-records>
        <h1>Object Environment Records</h1>

        <emu-clause id=sec-object-environment-records-hastopicbinding>
          <h1><ins>HasTopicBinding ( )</ins></h1>

          <emu-note type=editor>
          <p>This section is a wholly new sub-clause of the <a
          href=https://tc39.github.io/ecma262/#sec-object-environment-records>
          original Object Environment Records clause</a>.</p>
          </emu-note>

          <p>An Object Environment Record may never have a topic binding.</p>
          <emu-alg>
            1. Return *false*.
          </emu-alg>
          </emu-clause>
      </emu-clause>

      <emu-clause id=sec-global-environment-records>
          <h1>Global Environment Records</h1>

          <emu-clause id=sec-global-environment-records-hastopicbinding>
            <h1><ins>HasTopicBinding ( )</ins></h1>

            <emu-note type=editor>
              <p>This section is a wholly new sub-clause of the <a
              href=https://tc39.github.io/ecma262/#sec-object-environment-records>
              original Global Environment Records clause</a>.</p>
            </emu-note>

            <p>A Global Environment Record may never have a topic binding.</p>
            <emu-alg>
              1. Return *false*.
            </emu-alg>
          </emu-clause>
        </emu-clause>
    </emu-clause>

    <emu-clause id=sec-topic-bindings>
      <h1><ins>Topic Bindings</ins></h1>

      <emu-note type=editor>
        <p>This section is a wholly new sub-clause of the <a
        href=https://tc39.github.io/ecma262/#sec-environment-records>original
        Environment Records clause</a>.</p>

        <p>It presumptively uses `%` as the placeholder token for the
        topic reference. This choice of token is not a final decision; `%`
        could instead be `^` or some other token.</p>
      </emu-note>

      <p>The <dfn>topic binding</dfn> of a declarative Environment Record
      immutably binds the topic reference `%` to one value of any
      ECMAScript language type (called the <dfn>topic value</dfn> or simply
      the <dfn>topic</dfn>), within that declarative Environment Record, at
      the time of the Environment Record's instantiation. The topic of a
      declarative Environment Record conceptually serves as the value that its
      lexical context is "about".</p>

      <p>A <dfn>topic-binding environment</dfn> is a declarative Environment
      Record that establishes a topic binding.
      The <dfn>topic environment</dfn> of the running execution context is its
      LexicalEnvironment's innermost Environment Record that is also a
      topic-binding environment (or *null* if no such Environment Record
      exists), as defined by the abstract operator GetTopicEnvironment.</p>

      <emu-note>
        <p>An Environment Record is a topic-binding environment
        <strong>only</strong> when it is a declarative Environment Record that
        was created by a |PipeBody|.</p>
      </emu-note>
    </emu-clause>
  </emu-clause>

  <emu-clause id="sec-execution-contexts">
    <h1>Execution Contexts</h1>

    <emu-note type=editor>
      <p>This section augments the <a
      href=https://tc39.es/ecma262/#sec-execution-contexts>original
      Execution Contexts clause</a>.</p>
    </emu-note>

    <emu-clause id="sec-evaluatewithtopics" type="abstract operation">
      <h1>
        EvaluateWithTopics (
          _topicValues_: a List,
          _expression_: a Parse Node,
        )
      </h1>
      <dl class="header"></dl>
      <emu-alg>
        1. Assert: _topicValues_ is a List.
        1. Let _outerEnv_ be the running execution context's LexicalEnvironment.
        1. Let _topicEnv_ be NewDeclarativeEnvironment(_outerEnv_).
        1. Perform ! _topicEnv_.BindTopicValues(_topicValues_).
        1. Set the running execution context's LexicalEnvironment to
           _topicEnv_.
        1. Let _result_ be the result of evaluating _expression_.
        1. Set the running execution context's LexicalEnvironment to _outerEnv_.
        1. Return _result_.
      </emu-alg>
      <emu-note>
        <p>EvaluateWithTopics creates a new topic-binding environment and
        evaluates the given _expression_ with that as its topic environment.
        The previous Lexical Environment is restored afterward.</p>
      </emu-note>
    </emu-clause>

    <emu-clause id=sec-gettopicenvironment type="abstract operation">
      <h1>GetTopicEnvironment ( )</h1>
      <dl class="header"></dl>
      <emu-alg>
      1. Let _envRec_ be the running execution context's LexicalEnvironment.
      1. Repeat,
        1. Let _status_ be _envRec_.HasTopicBinding().
        1. If _status_ is *true*, return _envRec_.
        1. If _envRec_ is a global Environment Record, return *null*.
        1. Let _outer_ be the value of _envRec_.[[OuterEnv]].
        1. Set _envRec_ to _outer_.
      1. Return _envRec_.
      </emu-alg>
      <emu-note>
        <p>GetTopicEnvironment returns the running execution context's topic environment
        (i.e., its LexicalEnvironment's innermost topic-binding environment)
        or *null* if the running execution context has no topic binding.</p>
      </emu-note>
    </emu-clause>

    <emu-clause id=sec-getprimarytopicvalue type="abstract operation">
      <h1>GetPrimaryTopicValue ( )</h1>
      <dl class="header"></dl>
      <emu-alg>
      1. Let _topicEnv_ be GetTopicEnvironment().
      1. Assert: _topicEnv_ is a declarative Environment Record.
      1. Assert: _topicEnv_.HasTopicBinding() is *true*.
      1. Let _topicValues_ be _envRec_.[[TopicValues]].
      1. Assert: _topicValues_ has at least one element.
      1. Return _topicValues_[0].
      </emu-alg>
      <emu-note>
        <p>GetPrimaryTopicValue returns the topic value
        of the running execution context's topic environment.
        It may be called only when the running execution context's topic environment
        is not *null*.</p>
      </emu-note>
    </emu-clause>
  </emu-clause>
</emu-clause>

<emu-clause id=sec-ecmascript-language-lexical-grammar>
  <h1>ECMAScript Language: Lexical Grammar</h1>

  <emu-clause id=sec-punctuators>
    <h1>Punctuators</h1>

    <emu-note type=editor>
      <p>This section augments the <a
      href=https://tc39.github.io/ecma262/#sec-punctuators>original
      Punctuators clause</a>.</p>

      <p>It presumptively uses `%` as the placeholder token for the
      topic reference. This choice of token is not a final decision; `%`
      could instead be `^` or some other token.</p>
    </emu-note>

    <emu-grammar>
      OtherPunctuator :: one of
        `{` `(` `)` `[` `]`
        `.` `...` `;` `,`
        `&lt;` `&gt;` `&lt;=` `&gt;=`
        `==` `!=` `===` `!==`
        `+` `-` `*` `%` `**`
        `++` `--`
        `&lt;&lt;` `&gt;&gt;` `&gt;&gt;&gt;`
        `&amp;` `|` `%`
        `!` `~`
        `&amp;&amp;` `||` `??`
        `?` `:`
        <ins>`|&gt;`</ins>
        `=` `+=` `-=` `*=` <del>`%=`</del> `**=`
        `&lt;&lt;=` `&gt;&gt;=` `&gt;&gt;&gt;=` `&amp;=` `|=` `^=`
        `&amp;&amp;=` `||=` `??=`
        `=&gt;`

      DivPunctuator ::
        `/`
        `/=`
        <ins>`%=`</ins>
    </emu-grammar>
  </emu-clause>
</emu-clause>

<emu-clause id=sec-ecmascript-language-expressions>
  <h1>ECMAScript Language: Expressions</h1>

  <emu-clause id=sec-primary-expression>
    <h1>Primary Expression</h1>

    <emu-note type=editor>
      <p>This section augments the <a
      href=https://tc39.github.io/ecma262/#sec-primary-expression>original
      Primary Expression clause</a>.</p>

      <p>It presumptively uses `%` as the placeholder token for the
      topic reference. This choice of token is not a final decision; `%`
      could instead be `^` or some other token.</p>
    </emu-note>

    <h2>Syntax</h2>
    <emu-grammar type="definition">
      PrimaryExpression[Yield, Await] :
        `this`
        <ins>`%`</ins>
        IdentifierReference[?Yield, ?Await]
        Literal
        ArrayLiteral[?Yield, ?Await]
        ObjectLiteral[?Yield, ?Await]
        FunctionExpression
        ClassExpression[?Yield, ?Await]
        GeneratorExpression
        AsyncFunctionExpression
        AsyncGeneratorExpression
        RegularExpressionLiteral
        TemplateLiteral[?Yield, ?Await, ~Tagged]
        CoverParenthesizedExpressionAndArrowParameterList[?Yield, ?Await]
    </emu-grammar>

    <emu-clause id=sec-topic-references>
      <h1><ins>Topic Reference</ins></h1>

      <emu-note type=editor>
        <p>This section is a wholly new sub-clause to be inserted between the <a
        href=https://tc39.github.io/ecma262/#sec-this-keyword>original `this`
        Keyword clause</a> and the <a
        href=https://tc39.github.io/ecma262/#sec-identifier-reference>original
        Identifier Reference clause</a>.</p>

        <p>It presumptively uses `%` as the placeholder token for the
        topic reference. This choice of token is not a final decision; `%`
        could instead be `^` or some other token.</p>
      </emu-note>

      <emu-note>
        <p>The <dfn>topic reference</dfn>, which is the token `%`, is a
        nullary operator that evaluates to the current Environment Record's
        topic value. The topic reference acts as if it were a special variable,
        implicitly bound to the topic value, yet still lexically scoped. But
        `%` is not actually an |IdentifierName| and the topic reference is
        not a variable, and it cannot be bound by typical assignment.
        Instead, the topic reference is immutably bound to a value
        during the instantiation of any topic-binding environment by a |PipeBody|.</p>

        <p>The concept of the topic binding is further discussed in <emu-xref
        href="#sec-topic-bindings">Topic Bindings</emu-xref> and in <emu-xref
        href="#sec-declarative-environment-records">Declarative Environment
        Records</emu-xref>.</p>
      </emu-note>

      <emu-note>
        <p>An <dfn>unbound topic reference</dfn> is a topic reference that
        is not present within any topic-binding environment created by a |PipeBody|.
        All unbound topic references are invalid syntax.
        Several early error rules for |ScriptBody| and for
        |ModuleItemList|, as well as a step in CreateDynamicFunction,
        use ContainsOuterTopic to check for any unbound topic reference `%`.
        Any inner topic reference within a |PipeBody| is hidden from these rules,
        preventing them from triggering the rules during program
        compilation.</p>

        <p>This guarantees that every topic reference in a program must be
        present within a topic-binding environment
        created by a |PipeBody| within that program.</p>
      </emu-note>

      <emu-clause id=sec-topic-references-runtime-semantics-evaluation>
        <h1>Runtime Semantics: Evaluation</h1>
        <emu-note>
          <p>A topic reference may be evaluated only when
          the running execution context's topic environment is not *null*.
          This is syntactically enforced by early error rules
          for |ScriptBody| and for |ModuleItemList|,
          as well as a step in CreateDynamicFunction.
          These rules use ContainsOuterTopic to check for any unbound topic reference.</p>
        </emu-note>

        <emu-grammar>PrimaryExpression : `%`</emu-grammar>
        <emu-alg>
        1. Return GetPrimaryTopicValue().
        </emu-alg>
      </emu-clause>
    </emu-clause>
  </emu-clause>

  <emu-clause id=sec-pipe-operator>
    <h1><ins>Pipe Operator</ins></h1>

    <emu-note type=editor>
      <p>This section is a wholly new sub-clause to be inserted between the <a
      href=https://tc39.github.io/ecma262/#sec-conditional-operator>original
      Conditional Operator (`?` `:`) clause</a> and the <a
      href=https://tc39.github.io/ecma262/#sec-assignment-operators>original
      Assignment Operators clause</a>.</p>
    </emu-note>

    <h2>Syntax</h2>
    <emu-grammar type=definition>
      PipeExpression[In, Yield, Await] :
        ShortCircuitExpression[?In, ?Yield, ?Await] `|&gt;` PipeBody[?In, ?Yield, ?Await]

      PipeBody[In, Yield, Await] :
        AssignmentExpression[?In, ?Yield, ?Await]
    </emu-grammar>

    <emu-clause id=sec-pipe-operator-static-semantics-early-errors>
      <h1>Static Semantics: Early Errors</h1>
      <emu-note type=editor>
        <p>This section is a wholly new sub-clause.</p>

        <p>It presumptively uses `%` as the placeholder token for the
        topic reference. This choice of token is not a final decision; `%`
        could instead be `^` or some other token.</p>
      </emu-note>

      <emu-grammar>PipeBody : AssignmentExpression</emu-grammar>
      <emu-alg>
        1. It is a Syntax Error if |PipeBody| ContainsOuterTopic is *false*.
      </emu-alg>

      <emu-note>
        <p>A |PipeBody| must use its topic at least once.
        `value |&gt; foo + 1` is an early error,
        because ContainsOuterTopic of its |PipeBody| is *false*.
        This design is such because omission of any topic reference from a |PipeBody|
        is almost certainly an accidental programmer error.</p>
      </emu-note>

      <emu-grammar>PipeBody : AssignmentExpression</emu-grammar>
      <emu-alg>
        1. It is a Syntax Error if one of the following productions is covering |PipeBody|:
            * |ShortCircuitExpression| ? |AssignmentExpression| : |AssignmentExpression|
            * |YieldExpression|
            * |ArrowFunction|
            * |AsyncArrowFunction|
            * |LeftHandSideExpression| `=` |AssignmentExpression|
            * |LeftHandSideExpression| |AssignmentOperator| |AssignmentExpression|
            * |LeftHandSideExpression| `&&=` |AssignmentExpression|
            * |LeftHandSideExpression| `||=` |AssignmentExpression|
            * |LeftHandSideExpression| `??=` |AssignmentExpression|
      </emu-alg>

      <emu-note>
        <p>A |PipeBody| must not be an unparenthesized |AssignmentExpression|, such as |YieldExpression|, |ArrowFunction|, or |ConditionalExpression|—unless it is a |ShortCircuitExpression|.</p>
        <p>This is to prevent confusing expressions from being valid, such as:</p>
        <pre><code class="javascript">
          x |> yield % |> % + 1 // Syntax Error
        </code></pre>
        <p>This expression would otherwise be equivalent to:</p>
        <pre><code class="javascript">
          x |> (yield % |> % + 1)
        </code></pre>
        <p>Likewise, this expression:</p>
        <pre><code class="javascript">
          x |> y ? % : z |> % + 1 // Syntax Error
        </code></pre>
        <p>…would otherwise be equivalent to:</p>
        <pre><code class="javascript">
          x |> (y ? % : z |> % + 1)
        </code></pre>
        <p>These expressions are visually unclear and are therefore made invalid. The developer may make them valid with explicit parentheses:</p>
        <pre><code class="javascript">
          x |> (yield %) |> % + 1
          x |> (yield % |> % + 1)
          x |> (y ? % : z) |> % + 1
          x |> (y ? % : z |> % + 1)
        </code></pre>
      </emu-note>
    </emu-clause>

    <emu-clause id=sec-pipe-operator-runtime-semantics-evaluation>
    <h1>Runtime Semantics: Evaluation</h1>

    <emu-grammar>PipeExpression : ConditionalExpression `|&gt;` PipeBody</emu-grammar>
    <emu-alg>
      1. Let _inputRef_ be the result of evaluating _ConditionalExpression_.
      1. Let _inputValues_ be « ? GetValue(_inputRef_) ».
      1. Let _outputValue_ be ? EvaluateWithTopics(_inputValues_, |PipeBody|).
      1. Return _outputValue_.
    </emu-alg>
    </emu-clause>
  </emu-clause>
</emu-clause>

<emu-clause id="sec-ecmascript-language-scripts-and-modules">
  <h1>ECMAScript Language: Scripts and Modules</h1>

  <emu-clause id="sec-scripts">
    <h1>Scripts</h1>

    <emu-note type=editor>
      <p>This section augments the <a
      href=https://tc39.github.io/ecma262/#sec-scripts>original
      Scripts clause</a>.</p>

      <p>It presumptively uses `%` as the placeholder token for the
      topic reference. This choice of token is not a final decision; `%`
      could instead be `^` or some other token.</p>
    </emu-note>

    <emu-clause id="sec-scripts-static-semantics-early-errors">
      <h1>Static Semantics: Early Errors</h1>

      <emu-grammar>Script : ScriptBody</emu-grammar>
      <ul>
        <li>
          <ins>It is a Syntax Error if ContainsOuterTopic of |ScriptBody| is *true*.</ins>
        </li>
      </ul>
      <ins class="block">
      <emu-note>
        <p>An early error rule uses ContainsOuterTopic
        to check for any unbound topic reference.
        Any inner topic reference within a |PipeBody| is hidden from this rule,
        preventing them from triggering the rule during program
        compilation.</p>

        <p>This guarantees that every topic reference in a |Script| must be
        present within a topic-binding environment created
        by a |PipeBody| within that |Script|.</p>
      </emu-note>
      </ins>
    </emu-clause>
  </emu-clause>

  <emu-clause id="sec-modules">
    <h1>Modules</h1>

    <emu-clause id="sec-module-semantics">
      <h1>Module Semantics</h1>

      <emu-note type=editor>
        <p>This section augments the <a
        href=https://tc39.github.io/ecma262/#sec-module-semantics>original
        Module Semantics clause</a>.</p>

        <p>It presumptively uses `%` as the placeholder token for the
        topic reference. This choice of token is not a final decision; `%`
        could instead be `^` or some other token.</p>
      </emu-note>

      <emu-clause id="sec-module-semantics-static-semantics-early-errors">
        <h1>Static Semantics: Early Errors</h1>
        <emu-grammar>ModuleBody : ModuleItemList</emu-grammar>
        <ul>
          <li>
            <ins>It is a Syntax Error if ContainsOuterTopic of |ModuleItemList|
            is *true*.</ins>
          </li>
        </ul>

        <ins class="block">
        <emu-note>
          <p>An early error rule uses ContainsOuterTopic
          to check for any unbound topic reference.
          Any inner topic reference within a |PipeBody| is hidden from this rule,
          preventing them from triggering the rule during program
          compilation.</p>

          <p>This guarantees that every topic reference in a |ModuleBody| must be
          present within a topic-binding environment created
          by a |PipeBody| within that |ModuleBody|.</p>
        </emu-note>
        </ins>
      </emu-clause>
    </emu-clause>
  </emu-clause>
</emu-clause>

<emu-clause id="sec-fundamental-objects">
  <h1>Fundamental Objects</h1>

  <emu-clause id="sec-function-objects">
    <h1>Function Objects</h1>

    <emu-clause id="sec-function-constructor">
      <h1>The Function Constructor</h1>

      <emu-clause id="sec-function-p1-p2-pn-body">
        <h1>Function ( _p1_, _p2_, &hellip; , _pn_, _body_ )</h1>

        <emu-clause id="sec-createdynamicfunction" aoid="CreateDynamicFunction">
          <h1>CreateDynamicFunction ( _constructor_, _newTarget_, _kind_, _args_ )</h1>
          <emu-note type=editor>
            <p>This section augments the <a
            href=https://tc39.github.io/ecma262/#sec-createdynamicfunction>original
            CreateDynamicFunction clause</a>.</p>

            <p>It presumptively uses `%` as the placeholder token for the
            topic reference. This choice of token is not a final decision; `%`
            could instead be `^` or some other token.</p>
          </emu-note>

          <emu-alg>
            1. Assert: The execution context stack has at least two elements.
            1. Let _callerContext_ be the second to top element of the execution context stack.
            1. Let _callerRealm_ be _callerContext_'s Realm.
            1. Let _calleeRealm_ be the current Realm Record.
            1. Perform ? HostEnsureCanCompileStrings(_callerRealm_, _calleeRealm_).
            1. If _newTarget_ is *undefined*, set _newTarget_ to _constructor_.
            1. If _kind_ is ~normal~, then
              1. Let _exprSym_ be the grammar symbol |FunctionExpression|.
              1. Let _bodySym_ be the grammar symbol |FunctionBody[~Yield, ~Await]|.
              1. Let _parameterSym_ be the grammar symbol |FormalParameters[~Yield, ~Await]|.
              1. Let _fallbackProto_ be *"%Function.prototype%"*.
            1. Else if _kind_ is ~generator~, then
              1. Let _exprSym_ be the grammar symbol |GeneratorExpression|.
              1. Let _bodySym_ be the grammar symbol |GeneratorBody|.
              1. Let _parameterSym_ be the grammar symbol |FormalParameters[+Yield, ~Await]|.
              1. Let _fallbackProto_ be *"%GeneratorFunction.prototype%"*.
            1. Else if _kind_ is ~async~, then
              1. Let _exprSym_ be the grammar symbol |AsyncFunctionExpression|.
              1. Let _bodySym_ be the grammar symbol |AsyncFunctionBody|.
              1. Let _parameterSym_ be the grammar symbol |FormalParameters[~Yield, +Await]|.
              1. Let _fallbackProto_ be *"%AsyncFunction.prototype%"*.
            1. Else,
              1. Assert: _kind_ is ~asyncGenerator~.
              1. Let _exprSym_ be the grammar symbol |AsyncGeneratorExpression|.
              1. Let _bodySym_ be the grammar symbol |AsyncGeneratorBody|.
              1. Let _parameterSym_ be the grammar symbol |FormalParameters[+Yield, +Await]|.
              1. Let _fallbackProto_ be *"%AsyncGeneratorFunction.prototype%"*.
            1. Let _argCount_ be the number of elements in _args_.
            1. Let _P_ be the empty String.
            1. If _argCount_ = 0, let _bodyArg_ be the empty String.
            1. Else if _argCount_ = 1, let _bodyArg_ be _args_[0].
            1. Else,
              1. Assert: _argCount_ &gt; 1.
              1. Let _firstArg_ be _args_[0].
              1. Set _P_ to ? ToString(_firstArg_).
              1. Let _k_ be 1.
              1. Repeat, while _k_ &lt; _argCount_ - 1,
                1. Let _nextArg_ be _args_[_k_].
                1. Let _nextArgString_ be ? ToString(_nextArg_).
                1. Set _P_ to the string-concatenation of _P_, *","* (a comma), and _nextArgString_.
                1. Set _k_ to _k_ + 1.
              1. Let _bodyArg_ be _args_[_k_].
            1. Let _bodyString_ be the string-concatenation of 0x000A (LINE FEED), ? ToString(_bodyArg_), and 0x000A (LINE FEED).
            1. Let _prefix_ be the prefix associated with _kind_ in <emu-xref href="#sec-createdynamicfunction"></emu-xref>.
            1. Let _sourceString_ be the string-concatenation of _prefix_, *" anonymous("*, _P_, 0x000A (LINE FEED), *") {"*, _bodyString_, and *"}"*.
            1. Let _sourceText_ be ! StringToCodePoints(_sourceString_).
            1. Let _parameters_ be ParseText(! StringToCodePoints(_P_), _parameterSym_).
            1. If _parameters_ is a List of errors, throw a *SyntaxError* exception.
            1. Let _body_ be ParseText(! StringToCodePoints(_bodyString_), _bodySym_).
            1. If _body_ is a List of errors, throw a *SyntaxError* exception.
            1. NOTE: The parameters and body are parsed separately to ensure that each is valid alone. For example, `new Function("/*", "*/ ) {")` is not legal.
            1. NOTE: If this step is reached, _sourceText_ must match _exprSym_ (although the reverse implication does not hold). The purpose of the next two steps is to enforce any Early Error rules which apply to _exprSym_ directly.
            1. Let _expr_ be ParseText(_sourceText_, _exprSym_).
            1. If _expr_ is a List of errors, throw a *SyntaxError* exception.
            1. <ins>NOTE: The dynamic function must not contain an unbound topic reference `%`.)</ins>
            1. <ins>If ContainsOuterTopic of _expr_ is *true*, throw a *SyntaxError* exception.</ins>
            1. Let _proto_ be ? GetPrototypeFromConstructor(_newTarget_, _fallbackProto_).
            1. Let _realmF_ be the current Realm Record.
            1. Let _scope_ be _realmF_.[[GlobalEnv]].
            1. Let _privateScope_ be *null*.
            1. Let _F_ be ! OrdinaryFunctionCreate(_proto_, _sourceText_, _parameters_, _body_, ~non-lexical-this~, _scope_, _privateScope_).
            1. Perform SetFunctionName(_F_, *"anonymous"*).
            1. If _kind_ is ~generator~, then
              1. Let _prototype_ be ! OrdinaryObjectCreate(%GeneratorFunction.prototype.prototype%).
              1. Perform DefinePropertyOrThrow(_F_, *"prototype"*, PropertyDescriptor { [[Value]]: _prototype_, [[Writable]]: *true*, [[Enumerable]]: *false*, [[Configurable]]: *false* }).
            1. Else if _kind_ is ~asyncGenerator~, then
              1. Let _prototype_ be ! OrdinaryObjectCreate(%AsyncGeneratorFunction.prototype.prototype%).
              1. Perform DefinePropertyOrThrow(_F_, *"prototype"*, PropertyDescriptor { [[Value]]: _prototype_, [[Writable]]: *true*, [[Enumerable]]: *false*, [[Configurable]]: *false* }).
            1. Else if _kind_ is ~normal~, perform MakeConstructor(_F_).
            1. NOTE: Functions whose _kind_ is ~async~ are not constructible and do not have a [[Construct]] internal method or a *"prototype"* property.
            1. Return _F_.
          </emu-alg>
        </emu-clause>
      </emu-clause>
    </emu-clause>
  </emu-clause>
</emu-clause>
